package regex;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.spire.ms.System.Collections.ArrayList;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 日志文件分析
 *
 * @author: zhanglu
 * @date: 2023/12/19 15:49
 * @modify: 修改人信息, 修改内容 2023/12/19 15:49
 */
@Slf4j
public class LogFileAnalysis {

    private static final  ExecutorService executorService = Executors.newFixedThreadPool(2);
    private static final  ExecutorService workExecutorService = Executors.newFixedThreadPool(6);

    public static void main(String[] args) {
//        signExcelHandle();
//        if(true){
//               return;
//        }
        String res = FileUtil.readUtf8String("/Users/zhanglu/Desktop/1.txt");
        String data = JSONUtil.parseObj(res).getStr("data");
        System.out.println(data);
        FileUtil.writeBytes(Base64.decode(data), "/Users/zhanglu/Desktop/015.pdf");
        if(true){
            return;
        }
        String index = "0000_0016";
        String title = "（外网）0125-" + index;
        String path = "/Users/zhanglu/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/c9a1c762ab6161f8ffce2831a28327a2/Message/MessageTemp/449c5db469d85bf4b812fecab722ca5f/File/20240125/111/";
        List<String> logs = new ArrayList();
        for (File file : FileUtil.file(path).listFiles()) {
            if(file.isDirectory()){
                continue;
            }
            logs.addAll(FileUtil.readUtf8Lines(file));
        }
        FileUtil.writeUtf8Lines(logs, path + index + File.separator + "顺序日志-"+title+".txt");
        //按照时间排序
        AtomicInteger idx = new AtomicInteger(0);
        AtomicReference<String> dateTime = new AtomicReference<>(DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_MS_PATTERN));
        AtomicReference<String> threadNoAtom = new AtomicReference<>("[http-nio-]");
        AtomicReference<String> addressAtom = new AtomicReference<>("[ip:port]");
        List<String> lines = logs.stream().map(o -> {
            String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", o);
            if(ObjectUtil.isNotEmpty(dateTimeItem)){
                dateTime.set(dateTimeItem);
            }
            List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", o, 0);
            Optional<String> first = words.stream().filter(w -> w.contains("http-nio-")).findFirst();
            if(first.isPresent()){
                threadNoAtom.set(first.get());
            }
            Optional<String> first2 = words.stream().filter(w -> ReUtil.isMatch("\\[[0-9|.]{0,20}:[0-9]{0,10}\\]", w)).findFirst();
            if(first2.isPresent()){
                addressAtom.set(first2.get());
            }
            idx.incrementAndGet();
            log.info("构建:" + idx.get());
            return "[" + dateTime.get() + "]" + addressAtom.get() + threadNoAtom.get() + o;
        }).collect(Collectors.toList());
        CountDownLatch countDownLatch = new CountDownLatch(4);
        proxy(0, countDownLatch, x -> exceptionStatistic(lines, path + index + File.separator + "电子签章日志-异常统计-"+title+".txt"));
        proxy(0, countDownLatch, x -> suwellOfficeBug01(lines, path + index + File.separator + "用章-金山Office转版服务BUG-"+title+".txt"));
        proxy(0, countDownLatch, x -> udsDownloadBug01(lines, path + index + File.separator + "UDS下载失败BUG-"+title+".txt"));
        proxy(0, countDownLatch, x -> udsUploadBug01(lines, path + index + File.separator + "UDS上传失败BUG-"+title+".txt"));
        try {
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("排序...");
//        List<String> sortLines = lines.stream().sorted((o1, o2) -> {
//            String dateTime01 = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", o1);
//            String dateTime02 = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", o2);
//            return dateTime01.compareTo(dateTime02);
//        }).collect(Collectors.toList());
        List<String>  sortLines = lines;
        FileUtil.writeUtf8Lines(sortLines, path + index + File.separator + "合并日志-"+title+".txt");
        countDownLatch = new CountDownLatch(1);
        proxy(1, countDownLatch, x -> getPdfPreviewBug01(sortLines, path + index + File.separator + "用章-未找到预览文件BUG-"+title+".txt"));
        try {
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        countDownLatch = new CountDownLatch(2);
        proxy(1, countDownLatch, x -> saveInstanceTaskBug01(sortLines, path + index + File.separator + "用章-请发起签章任务BUG-UDS下载慢-"+title+".txt"));
        proxy(1, countDownLatch, x -> saveInstanceTaskBug02(sortLines, path + index + File.separator + "用章-文件已进行签章不可再次编辑BUG"+title+".txt"));
        try {
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("okkk");
        executorService.shutdown();
        workExecutorService.shutdown();
    }

    public static void signExcelHandle(){
        ExcelReader reader = ExcelUtil.getReader("/Users/zhanglu/Desktop/四川印章列表.xls");
        List<Map<String, Object>> maps = reader.readAll();
        List<Map<String, Object>> update = new ArrayList();
        List<Map<String, Object>> collect = maps.stream().filter(o -> {
            String signature_file_img = (String) o.get("signature_file_img");
            Long status = (Long) o.get("status");
            Long delete_flag = (Long) o.get("delete_flag");
            if (ObjectUtil.isEmpty(signature_file_img) && status == 0 && delete_flag == 0) {
                return true;
            }
            return false;
        }).collect(Collectors.toList());
        System.out.println(JSONUtil.toJsonStr(collect));
        collect.forEach(o -> {
            Object id = o.get("id");
            update.add(MapUtil.<String, Object>builder().put("id", id).put("delete_flag", 0).build());
        });
        System.out.println(JSONUtil.toJsonStr(update));
    }

    public static void proxy(int sleep, CountDownLatch countDownLatch, Consumer consumer){
        if(sleep > 0){
            try {
                TimeUnit.SECONDS.sleep(sleep);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        executorService.execute(() -> {
            try {
                consumer.accept(null);
            } finally {
                countDownLatch.countDown();
            }
        });
    }

    /**
     * 提交签章bug
     * @param logs
     * @param outFile
     */
    public static void exceptionStatistic(List<String> logs, String outFile){
        List<String> res = new ArrayList();
        AtomicInteger idx = new AtomicInteger(0);
        List<String> lines = logs;
        List<String> exceptionCache = new ArrayList();
        Map<String, Integer> exceptionMap = new HashMap<>();
        Map<String, Map<String, Integer>> exceptionDateMap = new HashMap<>();
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if(!line.contains("]com.sgcc.ebuild2.exception.EBuild2Exception: ")){
                log.info("总计：{}, 当前：{}", lines.size(), i);
                continue;
            }
            res.add(line);
            String group0 = ReUtil.getGroup0("(?<=com.sgcc.ebuild2.exception.EBuild2Exception: ).{0,10000}", line);
            Integer v1 = exceptionMap.getOrDefault(group0, 0);
            exceptionMap.put(group0, v1 + 1);
            String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
            DateTime date = DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MINUTE_PATTERN);
            Map<String, Integer> dateMap = exceptionDateMap.getOrDefault(group0, new HashMap<String, Integer>(){{
                DateTime dateTmp = DateUtil.beginOfHour(date);
                List<DateTime> ds = DateUtil.rangeToList(DateUtil.offsetHour(dateTmp, - 24 * 7), DateUtil.offsetHour(dateTmp, 24 * 7), DateField.HOUR);
                for (int d = 0; d < ds.size(); d++) {
                    try {
                        DateTime d1 = ds.get(d);
                        DateTime d2 = ds.get(d + 1);
                        put(DateUtil.format(d1, DatePattern.NORM_DATETIME_MINUTE_PATTERN) + " ～ " + DateUtil.format(d2, DatePattern.NORM_DATETIME_MINUTE_PATTERN), 0);
                    } catch (Exception e) {}
                }
            }});
            String between = "xxx";
            Optional<String> first = dateMap.keySet().stream().filter(o -> {
                String[] split = o.split(" ～ ");
                DateTime d1 = DateUtil.parse(split[0], DatePattern.NORM_DATETIME_MINUTE_PATTERN);
                DateTime d2 = DateUtil.parse(split[1], DatePattern.NORM_DATETIME_MINUTE_PATTERN);
                if (d1.isBeforeOrEquals(date) && d2.isAfter(date)) {
                    return true;
                }
                return false;
            }).findFirst();
            if(first.isPresent()){
                between = first.get();
            }
            Integer v = dateMap.getOrDefault(between, 0);
            dateMap.put(between, v + 1);
            exceptionDateMap.put(group0, dateMap);
            List<String> exceptions  = new ArrayList();
            for (int j = i; j < lines.size(); j++) {
                String ex = lines.get(j);
                if(!ex.startsWith("\tat ") || ex.startsWith("[") || ((j - i) > 10000)){
                    break;
                }
                exceptions.add(ex);
            }
            String join = CharSequenceUtil.join(",", exceptions);
            if(!exceptionCache.contains(join)) {
                res.addAll(exceptions);
                exceptionCache.add(join);
            }
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        }
        log.info("总计1：{}", res.size());
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        exceptionMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            exceptionDateMap.get(o.getKey()).entrySet().stream().sorted((o1, o2) -> o2.getKey().compareTo(o1.getKey())).forEach(map -> {
                if(map.getValue() == 0){
                    return;
                }
                res.add(0, CharSequenceUtil.format("\t-【{}】：{}", map.getKey(), map.getValue()));
            });
            res.add(0, CharSequenceUtil.format("【异常:次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        exceptionMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【异常:次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        log.info("总计2：{}", res.size());
        FileUtil.writeUtf8Lines(res, outFile);
    }

    /**
     * 提交签章bug
     * @param logs
     * @param outFile
     */
    public static void saveInstanceTaskBug01(List<String> logs, String outFile){
        Map<String, List<String>> resMap = new ConcurrentHashMap<>();
        List<String> res = new ArrayList();
        //按照时间排序
        Map<Integer, String> saveBusinessDataMap = new HashMap<>();
        AtomicInteger idx = new AtomicInteger(0);
        AtomicInteger thread = new AtomicInteger(0);
        List<String> lines = logs.stream().map(o -> {
            if(o.contains("-请发起签章任务")){
                thread.incrementAndGet();
            }
            if((o.contains("【保存业务实例数据】") || o.contains("【保存业务实例文件】")) && o.contains("请求参数")){
                String req01 = ReUtil.getGroup0("(?<=\\【[保存业务实例数据|保存业务实例文件]{0,100}\\】-请求参数:).{0,1000000}", o);
                saveBusinessDataMap.put(idx.get(), req01);
            }
            idx.incrementAndGet();
            log.info("saveInstanceTaskBug01-构建:" + idx.get());
            return o;
        }).collect(Collectors.toList());
//        FileUtil.writeUtf8Lines(lines, "/Users/zhanglu/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/c9a1c762ab6161f8ffce2831a28327a2/Message/MessageTemp/449c5db469d85bf4b812fecab722ca5f/File/外网log_dcp-common-integrate-signature_20231219143044/2.log");
        Map<String, Integer> wordTemplateIdMap = new HashMap<>();
        CountDownLatch countDownLatch = new CountDownLatch(thread.get());
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if(!line.contains("-请发起签章任务")){
                log.info("总计：{}, 当前：{}", lines.size(), i);
                continue;
            }
            int finalI = i;
            workExecutorService.execute(() -> {
                try {
                    List<String> resItem = new ArrayList();
                    List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", line, 0);
                    String threadNo = words.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
                    String instanceId = "";
                    String wordTemplateId = "";
                    //向上查找
                    for (int j = finalI; j > 0; j--) {
                        String req01 = lines.get(j);
                        String group01 = ReUtil.getGroup0("(?<=\\【[提交签章|提交签章Plus|并行提交签章]{0,100}\\】-请求参数:).{0,1000000}", req01);
                        if(ObjectUtil.isEmpty(group01) || !req01.contains(threadNo)){
                            log.info("总计：{}, 当前：{}, 查提交：{}", lines.size(), finalI, j);
                            continue;
                        }
                        instanceId = JSONUtil.parseObj(group01).getStr("instanceId");
                        resItem.add("【instanceId：" + instanceId + "...start】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
                        //再向上查找更往前的日志，找到模版id
                        for (int k = j; k > 0; k--) {
                            if(!saveBusinessDataMap.containsKey(k)){
                                log.info("总计：{}, 当前：{}, 查提交：{}, 查保存：{}", lines.size(), finalI, j, k);
                                continue;
                            }
                            String req02 = lines.get(k);
                            String group02 = saveBusinessDataMap.get(k);
                            List<String> words2 = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", req02, 0);
                            String threadNo2 = words2.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
                            if(!req02.contains(threadNo2)){
                                log.info("总计：{}, 当前：{}, 查提交：{}", lines.size(), finalI, j);
                                continue;
                            }
                            String instanceId02 = JSONUtil.parseObj(group02).getStr("instanceId");
                            if(!instanceId02.equalsIgnoreCase(instanceId)){
                                log.info("总计：{}, 当前：{}, 查提交：{}, 查保存：{} -> {}", lines.size(), finalI, j, k, instanceId);
                                continue;
                            }
                            wordTemplateId = JSONUtil.parseObj(group02).getStr("wordTemplateId");
                            Integer v = wordTemplateIdMap.getOrDefault(wordTemplateId, 0);
                            wordTemplateIdMap.put(wordTemplateId, v + 1);
                            resItem.add(req02);
                            //查找uds下载慢
                            String eof02 = "";
                            Integer endL = k;
                            for (int l = k; l < lines.size(); l++) {
                                String req03 = lines.get(l);
                                if(ObjectUtil.isNotEmpty(eof02) && req03.contains(eof02)){
                                    endL = l;
                                    break;
                                }
                                if((!req03.contains(threadNo2) || !req03.contains("第三方系统调用成功")) && ObjectUtil.isEmpty(eof02)){
                                    log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}", lines.size(), finalI, j, k, l);
                                    continue;
                                }
                                resItem.add(req03);
                                eof02 = "[ebuild2-common-integrate-signature]";
                            }
                            for (int q = endL; q < lines.size(); q++) {
                                String req04 = lines.get(q);
                                if(req04.contains(threadNo2) && req04.contains("SgUdsServiceImpl") && req04.contains("soap请求耗时")){
                                    resItem.add(req04);
                                    break;
                                }
                                log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}, 查4：{}", lines.size(), finalI, j, k, endL, q);
                            }
                            break;
                        }
                        String group0 = ReUtil.getGroup0(".*\\-请求参数", req01);
                        resItem.add(group0 + "：" + instanceId);
                        break;
                    }
                    resItem.add(line);
                    resItem.add("【wordTemplateId：" + wordTemplateId + " -> instanceId：" + instanceId + "...end】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
                    if(ObjectUtil.isNotEmpty(resItem)){
                        String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
                        resMap.put(dateTimeItem, resItem);
                    }
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            return;
        }
        List<String> keys = resMap.keySet().stream().sorted().collect(Collectors.toList());
        for (int i = 0; i < keys.size(); i++) {
            int finalI = i;
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.addAll(resMap.get(keys.get(i)).stream().map(o -> "【" + (finalI + 1) + "】：" + o).collect(Collectors.toList()));
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        }
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        wordTemplateIdMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【模版编码:异常次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：UDS文件下载慢（下载的文件很久之前就已经上传好了）\n" +
                "现象：响应时间都超过5s\n" +
                "问题相关方：UDS\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：第一个接口(保存实例业务数据)请求未执行完，就请求下一个接口了(提交签章)；\n" +
                "原因分析：\n" +
                "    1.未加防抖    \n" +
                "    2.只在5s内防抖    \n" +
                "    3.外网操作，UDS下载存在5～10s的延迟且UDS负载高的时候也存在5s的延迟，保存实例业务数据接口，会下载模版文件，可能会超过5s；    \n" +
                "    4.传入了一个无效的实例id  \n" +
                "    5.未传实例id\n" +
                "解决方案：与签章有关的接口都做好防抖，前端可以集成架构组提供的进度条组件；（详情可参考：电子签章相关调整方案优化建议常见问题说明.docx）；\n" +
                "问题相关方：各专业组\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        FileUtil.writeUtf8Lines(res, outFile);
    }

    public static void getPdfPreviewBug01(List<String> logs, String outFile){
        Map<String, List<String>> resMap = new ConcurrentHashMap<>();
        List<String> res = new ArrayList();
        //按照时间排序
        Map<Integer, String> saveBusinessDataMap = new HashMap<>();
        AtomicInteger idx = new AtomicInteger(0);
        AtomicInteger thread = new AtomicInteger(0);
        List<String> lines = logs.stream().map(o -> {
            if(o.contains("-未找到预览文件，请重新提交业务数据")){
                thread.incrementAndGet();
            }
            if((o.contains("【保存业务实例数据】") || o.contains("【保存业务实例文件】")) && o.contains("请求参数")){
                String req01 = ReUtil.getGroup0("(?<=\\【[保存业务实例数据|保存业务实例文件]{0,100}\\】-请求参数:).{0,1000000}", o);
                saveBusinessDataMap.put(idx.get(), req01);
            }
            idx.incrementAndGet();
            log.info("getPdfPreviewBug01-构建:" + idx.get());
            return o;
        }).collect(Collectors.toList());
//        FileUtil.writeUtf8Lines(lines, "/Users/zhanglu/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/c9a1c762ab6161f8ffce2831a28327a2/Message/MessageTemp/449c5db469d85bf4b812fecab722ca5f/File/外网log_dcp-common-integrate-signature_20231219143044/2.log");
        Map<String, Integer> wordTemplateIdMap = new HashMap<>();
        Map<String, Integer> instanceIdMap = new HashMap<>();
        Map<String, Integer> fileIdMap = new HashMap<>();
        CountDownLatch countDownLatch = new CountDownLatch(thread.get());
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if(!line.contains("-未找到预览文件，请重新提交业务数据")){
                log.info("总计：{}, 当前：{}", lines.size(), i);
                continue;
            }
            int finalI = i;
            workExecutorService.execute(() -> {
                try {
                    List<String> resItem = new ArrayList();
                    List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", line, 0);
                    String threadNo = words.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
                    //向上查找
                    for (int j = finalI; j > 0; j--) {
                        String req01 = lines.get(j);
                        String group01 = ReUtil.getGroup0("(?<=\\【[预览签章文件]{0,100}\\】-请求参数:).{0,1000000}", req01);
                        if(ObjectUtil.isEmpty(group01) || !req01.contains(threadNo)){
                            log.info("总计：{}, 当前：{}, 查预览：{}", lines.size(), finalI, j);
                            continue;
                        }
                        String instanceId = JSONUtil.parseObj(group01).getStr("instanceId");
                        String wordTemplateId = JSONUtil.parseObj(group01).getStr("wordTemplateId");
                        String fileId = JSONUtil.parseObj(group01).getStr("fileId");
                        Integer v1 = instanceIdMap.getOrDefault(instanceId, 0);
                        instanceIdMap.put(instanceId, v1 + 1);
                        Integer v2 = wordTemplateIdMap.getOrDefault(wordTemplateId, 0);
                        wordTemplateIdMap.put(wordTemplateId, v2 + 1);
                        Integer v3 = fileIdMap.getOrDefault(fileId, 0);
                        fileIdMap.put(wordTemplateId, v3 + 1);
                        resItem.add("【wordTemplateId：" + wordTemplateId + " -> instanceId：" + instanceId + " -> fileId：" + fileId + "...start】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
                        if(!ObjectUtil.isAllEmpty(instanceId, fileId)){
                            //再向上查找更往前的日志，找到模版id
                            for (int k = j; k > 0; k--) {
                                if(!saveBusinessDataMap.containsKey(k)){
                                    log.info("总计：{}, 当前：{}, 查预览：{}, 查保存：{}", lines.size(), finalI, j, k);
                                    continue;
                                }
                                String req02 = lines.get(k);
                                String group02 = saveBusinessDataMap.get(k);
                                List<String> words2 = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", req02, 0);
                                String threadNo2 = words2.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
                                if(!req02.contains(threadNo2)){
                                    log.info("总计：{}, 当前：{}, 查提交：{}", lines.size(), finalI, j);
                                    continue;
                                }
                                String instanceId02 = JSONUtil.parseObj(group02).getStr("instanceId");
                                if(!instanceId02.equalsIgnoreCase(instanceId)){
                                    log.info("总计：{}, 当前：{}, 查提交：{}, 查保存：{} -> {}", lines.size(), finalI, j, k, instanceId);
                                    continue;
                                }
                                if(ObjectUtil.isNotEmpty(wordTemplateId)){
                                    Integer v = wordTemplateIdMap.getOrDefault(wordTemplateId, 0);
                                    wordTemplateIdMap.put(wordTemplateId, v + 1);
                                }
                                if(ObjectUtil.isNotEmpty(instanceId)){
                                    Integer v = instanceIdMap.getOrDefault(instanceId, 0);
                                    instanceIdMap.put(instanceId, v + 1);
                                }
                                if(ObjectUtil.isNotEmpty(fileId)){
                                    Integer v = fileIdMap.getOrDefault(fileId, 0);
                                    fileIdMap.put(fileId, v + 1);
                                }
                                resItem.add(req02);
                                //查找uds下载慢
                                String eof02 = "";
                                Integer endL = k;
                                for (int l = k; l < lines.size(); l++) {
                                    String req03 = lines.get(l);
                                    if(ObjectUtil.isNotEmpty(eof02) && req03.contains(eof02)){
                                        endL = l;
                                        break;
                                    }
                                    if((!req03.contains(threadNo2) || !req03.contains("第三方系统调用成功")) && ObjectUtil.isEmpty(eof02)){
                                        log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}", lines.size(), finalI, j, k, l);
                                        continue;
                                    }
                                    resItem.add(req03);
                                    eof02 = "[ebuild2-common-integrate-signature]";
                                }
                                for (int q = endL; q < lines.size(); q++) {
                                    String req04 = lines.get(q);
                                    if(req04.contains(threadNo2) && req04.contains("SgUdsServiceImpl") && req04.contains("soap请求耗时")){
                                        resItem.add(req04);
                                        break;
                                    }
                                    log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}, 查4：{}", lines.size(), finalI, j, k, endL, q);
                                }
                                break;
                            }
                        }
                        resItem.add(req01);
                        resItem.add(line);
                        resItem.add("【wordTemplateId：" + wordTemplateId + " -> instanceId：" + instanceId + " -> fileId：" + fileId + "...end】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
                        break;
                    }
                    if(ObjectUtil.isNotEmpty(resItem)){
                        String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
                        resMap.put(dateTimeItem, resItem);
                    }
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            return;
        }
        List<String> keys = resMap.keySet().stream().sorted().collect(Collectors.toList());
        for (int i = 0; i < keys.size(); i++) {
            int finalI = i;
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.addAll(resMap.get(keys.get(i)).stream().map(o -> "【" + (finalI + 1) + "】：" + o).collect(Collectors.toList()));
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        }
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        fileIdMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【文件id:异常次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        instanceIdMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【实例id:异常次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        wordTemplateIdMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【模版编码:异常次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：第一个接口(保存实例业务数据)请求未执行完，就请求下一个接口了(文件预览)；\n" +
                "原因分析：\n" +
                "    1.请求参数为空 \n" +
                "    2.未加防抖    \n" +
                "    3.只在5s内防抖    \n" +
                "    4.外网操作，UDS下载存在5～10s的延迟且UDS负载高的时候也存在5s的延迟，保存实例业务数据接口，会下载模版文件，可能会超过5s；\n" +
                "解决方案：与签章有关的接口都做好防抖，前端可以集成架构组提供的进度条组件；（详情可参考：电子签章相关调整方案优化建议常见问题说明.docx）；\n" +
                "问题相关方：各专业组\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        FileUtil.writeUtf8Lines(res, outFile);
    }

    public static void saveInstanceTaskBug02(List<String> logs, String outFile){
        Map<String, List<String>> resMap = new ConcurrentHashMap<>();
        List<String> res = new ArrayList();
        //按照时间排序
        Map<Integer, String> saveBusinessDataMap = new HashMap<>();
        AtomicInteger idx = new AtomicInteger(0);
        AtomicInteger thread = new AtomicInteger(0);
        List<String> lines = logs.stream().map(o -> {
            if(o.contains("-文件已进行签章，不可再次编辑")){
                thread.incrementAndGet();
            }
            if((o.contains("【提交签章】") || o.contains("【提交签章Plus】") || o.contains("【并行提交签章】")) && o.contains("请求参数")){
                String req01 = ReUtil.getGroup0(".*【[提交签章|提交签章Plus|并行提交签章]{0,100}】\\-请求参数", o);
                saveBusinessDataMap.put(idx.get(), req01);
            }
            idx.incrementAndGet();
            log.info("saveInstanceTaskBug02-构建:" + idx.get());
            return o;
        }).collect(Collectors.toList());
//        FileUtil.writeUtf8Lines(lines, "/Users/zhanglu/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/c9a1c762ab6161f8ffce2831a28327a2/Message/MessageTemp/449c5db469d85bf4b812fecab722ca5f/File/外网log_dcp-common-integrate-signature_20231219143044/2.log");
        Map<String, Integer> wordTemplateIdMap = new HashMap<>();
        Map<String, Integer> instanceIdMap = new HashMap<>();
        CountDownLatch countDownLatch = new CountDownLatch(thread.get());
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if(!line.contains("-文件已进行签章，不可再次编辑")){
                log.info("总计：{}, 当前：{}", lines.size(), i);
                continue;
            }
            int finalI = i;
            workExecutorService.execute(() -> {
                try {
                    List<String> resItem = new ArrayList();
                    List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", line, 0);
                    String threadNo = words.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
                    String instanceId = "";
                    String wordTemplateId = "";
                    for (int j = finalI; j > 0; j--) {
                        String req0 = lines.get(j);
                        String group01 = ReUtil.getGroup0("(?<=\\【[保存业务实例数据|保存业务实例文件]{0,100}\\】-请求参数:).{0,1000000}", req0);
                        if(req0.contains(threadNo) && (req0.contains("【保存业务实例数据】") || req0.contains("【保存业务实例文件】"))){
                            wordTemplateId = JSONUtil.parseObj(group01).getStr("wordTemplateId");
                            Integer v = wordTemplateIdMap.getOrDefault(wordTemplateId, 0);
                            wordTemplateIdMap.put(wordTemplateId, v + 1);
                            instanceId = JSONUtil.parseObj(group01).getStr("instanceId");
                            Integer v2 = instanceIdMap.getOrDefault(instanceId, 0);
                            instanceIdMap.put(wordTemplateId, v2 + 1);
                            resItem.add("【wordTemplateId：" + wordTemplateId + " -> instanceId：" + instanceId + "...start】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
                            resItem.add(req0);
                            break;
                        }
                        log.info("总计：{}, 当前：{}, 查保存：{}", lines.size(), finalI, j);
                    }
                    resItem.add(line);
                    //向上查找
                    for (int j = finalI; j > 0; j--) {
                        String req01 = lines.get(j);
                        if(!saveBusinessDataMap.containsKey(j)){
                            log.info("总计：{}, 当前：{}, 查提交：{}", lines.size(), finalI, j);
                            continue;
                        }
                        List<String> words1 = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", saveBusinessDataMap.get(j), 0);
                        String threadNo1 = words1.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
                        if(!req01.contains(threadNo1)){
                            log.info("总计：{}, 当前：{}, 查提交：{}", lines.size(), finalI, j);
                            continue;
                        }
                        resItem.add(saveBusinessDataMap.get(j) + "：" + instanceId);
                        for (int k = j; k < finalI; k++) {
                            String req02 = lines.get(k);
                            if(!req02.contains(threadNo1) || !req02.contains("soap请求耗时")){
                                log.info("总计：{}, 当前：{}, 查提交：{}, 查1：{}", lines.size(), finalI, j, k);
                                continue;
                            }
                            resItem.add(req02);
                            for (int l = k; l < finalI; l++) {
                                String req03 = lines.get(l);
                                if(!req03.contains(threadNo1) || !req03.contains("-sgUds上传参数")){
                                    log.info("总计：{}, 当前：{}, 查提交：{}, 查1：{}, 查2：{}", lines.size(), finalI, j, k, l);
                                    continue;
                                }
                                resItem.add(req03);
                                for (int q = l; q < finalI; q++) {
                                    String req04 = lines.get(q);
                                    if(!req04.contains(threadNo1) || !req04.contains("-上传共用时毫秒数")){
                                        log.info("总计：{}, 当前：{}, 查提交：{}, 查1：{}, 查2：{}, 查3：{}", lines.size(), finalI, j, k, l, q);
                                        continue;
                                    }
                                    resItem.add(req04);
                                    break;
                                }
                                break;
                            }
                            break;
                        }
                        break;
                    }
                    resItem.add("【wordTemplateId：" + wordTemplateId + " -> instanceId：" + instanceId + "...end】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
                    if(ObjectUtil.isNotEmpty(resItem)){
                        String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
                        resMap.put(dateTimeItem, resItem);
                    }
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            return;
        }
        List<String> keys = resMap.keySet().stream().sorted().collect(Collectors.toList());
        for (int i = 0; i < keys.size(); i++) {
            int finalI = i;
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.addAll(resMap.get(keys.get(i)).stream().map(o -> "【" + (finalI + 1) + "】：" + o).collect(Collectors.toList()));
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        }
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        instanceIdMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【实例id:异常次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        wordTemplateIdMap.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【模版编码:异常次数】{} ---> {}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：已经签过章的文件不允许更新内容（否则签章将失效）；\n" +
                "原因分析：1.业务问题调用过提交签章接口，则不能调保存业务实例数据接口；2.未加防抖 \n" +
                "解决方案：与签章有关的接口都做好防抖，前端可以集成架构组提供的进度条组件；（详情可参考：电子签章相关调整方案优化建议常见问题说明.docx）；\n" +
                "问题相关方：各专业组\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        FileUtil.writeUtf8Lines(res, outFile);
    }

    public static void suwellOfficeBug01(List<String> logs, String outFile){
        List<String> res = new ArrayList();
        //按照时间排序
        AtomicReference<String> dateTime = new AtomicReference<>(DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_MS_PATTERN));
        AtomicReference<String> threadNoAtom = new AtomicReference<>("[http-nio-]");
        List<String> lines = logs;
//        FileUtil.writeUtf8Lines(lines, "/Users/zhanglu/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/c9a1c762ab6161f8ffce2831a28327a2/Message/MessageTemp/449c5db469d85bf4b812fecab722ca5f/File/外网log_dcp-common-integrate-signature_20231219143044/2.log");
        Integer index = 1;
        Map<String, Integer> statistics = new LinkedHashMap<>();
        Map<String, Integer> formatStatistics = new LinkedHashMap<>();
        Map<String, Integer> fileNameStatistics = new LinkedHashMap<>();
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            try {
                if(!(line.contains("-请求调用异常:") && lines.get(i + 1).contains("com.sgcc.ebuild2.exception.EBuild2Exception: UDS60006-文件内容不能为空"))){
                    log.info("总计：{}, 当前：{}", lines.size(), i);
                    continue;
                }
            } catch (Exception e) {
                continue;
            }
            List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", line, 0);
            String threadNo = words.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            //向上查找
            String targetFileName = "";
            String targetFileFormat = "";
            String sourceFileName = "";
            String sourceFileFormat = "";
            for (int j = i; j > 0; j--) {
                String req01 = lines.get(j);
                if((i - j) > 10000){
                    break;
                }
                if(!req01.contains(threadNo) || !req01.contains("[com.sgcc.ebuild2.api.uds.impl.UdsUploadServiceImpl          :89]-UdsServiceInvokerImpl")){
                    log.info("总计：{}, 当前：{}, 查1：{}", lines.size(), i, j);
                    continue;
                }
                targetFileName = ReUtil.getGroup0("(?<=attachmentName=).* (?=multipartFile)", req01).replace(",", "").replace("\'", "").trim();
                targetFileFormat = FileUtil.extName(targetFileName);
                //再向上查找更往前的日志，找到模版id
                for (int k = j; k > 0; k--) {
                    String req02 = lines.get(k);
                    if((j - k) > 10000){
                        break;
                    }
                    if(!req02.contains(threadNo) || !req02.contains("action=end")
                            || !(req02.contains("/layoutToLayoutConvert") || req02.contains("/flowToLayoutPdfConvert") || req02.contains("/flowToLayoutOfdConvert"))){
                        log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}", lines.size(), i, j, k);
                        continue;
                    }
                    for (int q = k; q > 0; q--) {
                        String req03 = lines.get(q);
                        if((k - q) > 10000){
                            break;
                        }
                        if(!req03.contains(threadNo) || !req03.contains("action=start")
                                || !(req03.contains("/layoutToLayoutConvert") || req03.contains("/flowToLayoutPdfConvert") || req03.contains("/flowToLayoutOfdConvert"))){
                            log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}", lines.size(), i, j, k, q);
                            continue;
                        }
                        for (int l = q; l > 0; l--) {
                            String req04 = lines.get(l);
                            if((q - l) > 10000){
                                break;
                            }
                            if(!req04.contains(threadNo) || !req04.contains("-第三方系统调用成功, data=AttachmentInfoDTO")){
                                log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}, 查4：{}", lines.size(), i, j, k, q, l);
                                continue;
                            }
                            try {
                                sourceFileName = ReUtil.getGroup0("(?<=attachmentName=).* (?=attachmentType)", req04).replace(",", "").trim();
                                sourceFileFormat = ReUtil.getGroup0("(?<=attachmentType=).* (?=path)", req04).replace(",", "").trim();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            Integer v = formatStatistics.getOrDefault(CharSequenceUtil.format("{} -> {}", sourceFileFormat, targetFileFormat), 0);
                            formatStatistics.put(CharSequenceUtil.format("{} -> {}", sourceFileFormat, targetFileFormat), v + 1);
                            Integer v2 = fileNameStatistics.getOrDefault(CharSequenceUtil.format("{} -> {}", sourceFileName, targetFileName), 0);
                            fileNameStatistics.put(CharSequenceUtil.format("{} -> {}", sourceFileName, targetFileName), v2 + 1);
                            res.add("【" + index + "】：【sourceFileName：" + sourceFileName + " -> targetFileName：" + targetFileName + "...start】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
                            for (int w = l; w > 0; w--) {
                                String req05 = lines.get(w);
                                if((l - w) > 10000){
                                    break;
                                }
                                if(!req05.contains(threadNo) || !req05.contains("-上传共用时毫秒数")){
                                    log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}, 查4：{}, 查5：{}", lines.size(), i, j, k, q, l, w);
                                    continue;
                                }
                                for (int e = w; e > 0; e--) {
                                    String req06 = lines.get(e);
                                    if(!req06.contains(threadNo) || !req06.contains("-sgUds上传参数")){
                                        log.info("总计：{}, 当前：{}, 查1：{}, 查2：{}, 查3：{}, 查4：{}, 查5：{}, 查6：{}", lines.size(), i, j, k, q, l, w, e);
                                        continue;
                                    }
                                    res.add("【" + index + "】：" + req06);
                                    break;
                                }
                                res.add("【" + index + "】：" + req05);
                                break;
                            }
                            res.add("【" + index + "】：" + req04);
                            break;
                        }
                        res.add("【" + index + "】：" + req03);
                        break;
                    }
                    res.add("【" + index + "】：" + req02);
                    break;
                }
                res.add("【" + index + "】：" + req01);
                break;
            }
            res.add("【" + index + "】：" + line);
            res.add("【" + index + "】：【sourceFileName：" + sourceFileName + " -> targetFileName：" + targetFileName + "...end】----------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
            dateTimeItem = DateUtil.format(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MS_PATTERN), DatePattern.NORM_DATETIME_MINUTE_PATTERN);
            if(ObjectUtil.isEmpty(statistics)){
                statistics.put(dateTimeItem, 1);
            } else {
                List<String> keys = statistics.keySet().stream().collect(Collectors.toList());
                String k = keys.get(statistics.size() - 1);
                Integer v = statistics.get(k);
                //若相差20min，则新建，否则 v+1
                if(ObjectUtil.isNotEmpty(v) && DateUtil.offset(DateUtil.parse(k, DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20)
                        .isAfterOrEquals(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MINUTE_PATTERN))){
                    statistics.put(k, v + 1);
                }else {
                    statistics.put(dateTimeItem, 1);
                }
            }
            index++;
        }
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        fileNameStatistics.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【{}:异常次数】：{}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        formatStatistics.entrySet().stream().sorted((m1, m2) -> m1.getValue().compareTo(m2.getValue())).forEach(o -> {
            res.add(0, CharSequenceUtil.format("【{}:异常次数】：{}", o.getKey(), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        statistics.entrySet().stream().forEach(o -> {
            res.add(0, CharSequenceUtil.format("【{} ~ {}:异常次数】：{}", o.getKey(),
                    DateUtil.format(DateUtil.offset(DateUtil.parse(o.getKey(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20),
                            DatePattern.NORM_DATETIME_MINUTE_PATTERN ), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：金山Office转版服务异常\n" +
                "问题相关方：金山Office\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        FileUtil.writeUtf8Lines(res, outFile);
    }

    public static void udsDownloadBug01(List<String> logs, String outFile){
        List<String> res = new ArrayList();
        //按照时间排序
        AtomicReference<String> dateTime = new AtomicReference<>(DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_MS_PATTERN));
        AtomicReference<String> threadNoAtom = new AtomicReference<>("[http-nio-]");
        List<String> lines = logs;
//        FileUtil.writeUtf8Lines(lines, "/Users/zhanglu/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/c9a1c762ab6161f8ffce2831a28327a2/Message/MessageTemp/449c5db469d85bf4b812fecab722ca5f/File/外网log_integrate-signature_20231219201553/uds01.log");
        Integer index = 1;
        Map<String, Integer> statistics = new LinkedHashMap<>();
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if(!line.contains("-数据中台非结构化组件异常") || line.contains("-数据中台非结构化组件异常数据中台非结构化组件上传异常")){
                log.info("总计：{}, 当前：{}", lines.size(), i);
                continue;
            }
            List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", line, 0);
            String threadNo = words.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.add("【" + index + "】：【...start】---------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            //向上查找
            for (int j = i; j > 0; j--) {
                String req01 = lines.get(j);
                if((i - j) > 10000){
                    break;
                }
                if(!req01.contains(threadNo) || !req01.contains("sgUds文件下载上送参数")){
                    log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i, j);
                    continue;
                }
                String eof02 = "";
                for (int k = j; k > 0; k--) {
                    String req02 = lines.get(k);
                    if((j - k) > 10000){
                        break;
                    }
                    if((!req02.contains(threadNo) || !req02.contains("第三方系统调用成功")) && ObjectUtil.isEmpty(eof02)){
                        log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i, j);
                        continue;
                    }
                    for (int q = k; q < j; q++) {
                        String req03 = lines.get(q);
                        if(ObjectUtil.isNotEmpty(eof02) && req03.contains(eof02)){
                            break;
                        }
                        if((!req03.contains(threadNo)) && ObjectUtil.isEmpty(eof02)){
                            log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i, j);
                            continue;
                        }
                        res.add("【" + index + "】：" + req03);
                        eof02 = "[ebuild2-common-integrate-signature]";
                    }
                    break;
                }
                res.add("【" + index + "】：" + req01);
                break;
            }
            res.add("【" + index + "】：" + line);
            try {
                for (int l = 1; l <= 10; l++) {
                    res.add("【" + index + "】：" + lines.get(i + l));
                }
            } catch (Exception e) {}
            String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
            dateTimeItem = DateUtil.format(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MS_PATTERN), DatePattern.NORM_DATETIME_MINUTE_PATTERN);
            if(ObjectUtil.isEmpty(statistics)){
                statistics.put(dateTimeItem, 1);
            } else {
                List<String> keys = statistics.keySet().stream().collect(Collectors.toList());
                String k = keys.get(statistics.size() - 1);
                Integer v = statistics.get(k);
                //若相差20min，则新建，否则 v+1
                if(ObjectUtil.isNotEmpty(v) && DateUtil.offset(DateUtil.parse(k, DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20)
                        .isAfterOrEquals(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MINUTE_PATTERN))){
                    statistics.put(k, v + 1);
                }else {
                    statistics.put(dateTimeItem, 1);
                }
            }
            res.add("【" + index + "】：【...end】-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            index++;
            log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i);
        }
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        statistics.entrySet().stream().forEach(o -> {
            res.add(0, CharSequenceUtil.format("【{} ~ {}:异常次数】：{}", o.getKey(),
                    DateUtil.format(DateUtil.offset(DateUtil.parse(o.getKey(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20),
                            DatePattern.NORM_DATETIME_MINUTE_PATTERN ), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：UDS对端系统下载失败\n" +
                "问题相关方：UDS\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        FileUtil.writeUtf8Lines(res, outFile);
    }

    public static void udsUploadBug01(List<String> logs, String outFile){
        List<String> res = new ArrayList();
        //按照时间排序
        AtomicReference<String> dateTime = new AtomicReference<>(DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_MS_PATTERN));
        AtomicReference<String> threadNoAtom = new AtomicReference<>("[http-nio-]");
        List<String> lines = logs;
        Integer index = 1;
        Map<String, Integer> statistics = new LinkedHashMap<>();
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if(!line.contains("-非结构化上传报错")){
                log.info("总计：{}, 当前：{}", lines.size(), i);
                continue;
            }
            List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", line, 0);
            String threadNo = words.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.add("【" + index + "】：【...start】---------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            //向上查找
            for (int j = i; j > 0; j--) {
                String req01 = lines.get(j);
                if((i - j) > 10000){
                    break;
                }
                if(!req01.contains(threadNo) || !req01.contains("-sgUds上传参数")){
                    log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i, j);
                    continue;
                }
                res.add("【" + index + "】：" + req01);
                break;
            }
            res.add("【" + index + "】：" + line);
            try {
                for (int l = 1; l <= 10; l++) {
                    res.add("【" + index + "】：" + lines.get(i + l));
                }
            } catch (Exception e) {}
            String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
            dateTimeItem = DateUtil.format(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MS_PATTERN), DatePattern.NORM_DATETIME_MINUTE_PATTERN);
            if(ObjectUtil.isEmpty(statistics)){
                statistics.put(dateTimeItem, 1);
            } else {
                List<String> keys = statistics.keySet().stream().collect(Collectors.toList());
                String k = keys.get(statistics.size() - 1);
                Integer v = statistics.get(k);
                //若相差20min，则新建，否则 v+1
                if(ObjectUtil.isNotEmpty(v) && DateUtil.offset(DateUtil.parse(k, DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20)
                        .isAfterOrEquals(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MINUTE_PATTERN))){
                    statistics.put(k, v + 1);
                }else {
                    statistics.put(dateTimeItem, 1);
                }
            }
            res.add("【" + index + "】：【...end】-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            index++;
            log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i);
        }
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        statistics.entrySet().stream().forEach(o -> {
            res.add(0, CharSequenceUtil.format("【{} ~ {}:异常次数】：{}", o.getKey(),
                    DateUtil.format(DateUtil.offset(DateUtil.parse(o.getKey(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20),
                            DatePattern.NORM_DATETIME_MINUTE_PATTERN ), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：UDS对端系统上传失败\n" +
                "问题相关方：UDS\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        FileUtil.writeUtf8Lines(res, outFile);
    }

    public static void tymfBug01(List<String> logs, String outFile){
        List<String> res = new ArrayList();
        //按照时间排序
        AtomicReference<String> dateTime = new AtomicReference<>(DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_MS_PATTERN));
        AtomicReference<String> threadNoAtom = new AtomicReference<>("[http-nio-]");
        List<String> lines = logs;
        Integer index = 1;
        Map<String, Integer> statistics = new LinkedHashMap<>();
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if(!line.contains("-统一密服印章托管失败")){
                log.info("总计：{}, 当前：{}", lines.size(), i);
                continue;
            }
            List<String> words = ReUtil.findAll("\\[[A-Za-z0-9-:. ]*\\]", line, 0);
            String threadNo = words.stream().filter(o -> o.contains("http-nio-")).findFirst().get();
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.add("【" + index + "】：【...start】---------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            //向上查找
            for (int j = i; j > 0; j--) {
                String req01 = lines.get(j);
                if(!req01.contains(threadNo) || !req01.contains("[c.s.e.c.i.s.example.service.impl.SignatureClientServiceImpl") || !req01.contains("->统一密服印章托管返回结果：")){
                    log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i, j);
                    continue;
                }
                res.add("【" + index + "】：" + req01);
                break;
            }
            res.add("【" + index + "】：" + line);
            try {
                for (int l = 1; l <= 10; l++) {
                    res.add("【" + index + "】：" + lines.get(i + l));
                }
            } catch (Exception e) {}
            String dateTimeItem = ReUtil.getGroup0("([0-9]{4})-([0-9]{2})-([0-9]{2})\\s([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})", line);
            dateTimeItem = DateUtil.format(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MS_PATTERN), DatePattern.NORM_DATETIME_MINUTE_PATTERN);
            if(ObjectUtil.isEmpty(statistics)){
                statistics.put(dateTimeItem, 1);
            } else {
                List<String> keys = statistics.keySet().stream().collect(Collectors.toList());
                String k = keys.get(statistics.size() - 1);
                Integer v = statistics.get(k);
                //若相差20min，则新建，否则 v+1
                if(ObjectUtil.isNotEmpty(v) && DateUtil.offset(DateUtil.parse(k, DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20)
                        .isAfterOrEquals(DateUtil.parse(dateTimeItem, DatePattern.NORM_DATETIME_MINUTE_PATTERN))){
                    statistics.put(k, v + 1);
                }else {
                    statistics.put(dateTimeItem, 1);
                }
            }
            res.add("【" + index + "】：【...end】-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            res.add("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
            index++;
            log.info("总计：{}, 当前：{}, 查：{}", lines.size(), i);
        }
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        statistics.entrySet().stream().forEach(o -> {
            res.add(0, CharSequenceUtil.format("【{} ~ {}:异常次数】：{}", o.getKey(),
                    DateUtil.format(DateUtil.offset(DateUtil.parse(o.getKey(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), DateField.MINUTE, 20),
                            DatePattern.NORM_DATETIME_MINUTE_PATTERN ), o.getValue()));
        });
        res.add(0, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        res.add(0, "错误描述：统一密服印章托管异常\n" +
                "问题相关方：统一密服\n" +
                "日志分析人：架构组-张卢");
        res.add(0, "------------------------------------------------------------------------------------------------------------------------外网环境-------------------------------------------------------------------------------------");
        FileUtil.writeUtf8Lines(res, outFile);
    }

}
